#include "myc.h"

struct token *find_colon(struct token *st,struct token *end) {
	int nest=0;
	while ((st=find_leftest(st,end,"? :"))) {
		if (tokis(st,"?")) nest++;
		else if (tokis(st,":")) if (--nest == 0) return st;
		st=st->next;
	}
	return NULL;
}

void get_bintree(struct tree *me,struct token *st,struct token *end,struct token *pri) {
	if (!(me->down=gettree(st,pri))) tokerror(st,end,"cannon parse");
	if (!(me->down->next=gettree(pri->next,end))) tokerror(st,end,"cannon parse");
	me->to.token=binoper(pri);
	me->toket=-1;
}

struct tree *gettree(struct token *st,struct token *end) {
	struct token *pri;
	struct tree *me;
	if (st==end) return NULL;
	if (st->next==end) {
		me=calloc(1,sizeof(*me));
		me->toket=-2;
		me->to.token=st;
		typetree(me);
		return me;
	}
	if (tokis(st,"(") && endbr(st,end)==end->prev) {
		me=gettree(st->next,end->prev);
		if (!me || me->next) tokerror(st,end,"cannon parse");
		return me;
	}
	if ((pri=find_leftest(st,end,","))) {
		me=gettree(st,pri);
		if (!me || !(me->next=gettree(pri->next,end))) tokerror(st,end,"cannon parse");
		return me;
	}
	me=calloc(1,sizeof(*me));
	if (st->next!=end && is_alnum(*st->str) && tokis(st->next,"(") && (pri=endbr(st->next,end))->next==end) {
		me->down=gettree(st->next->next,pri);
		me->to.token=st;
		me->toket=-1;
	} else if ((pri=find_leftest(st,end,"= += -= *= /= %= &= |= <<= >>= ^="))) {
		get_bintree(me,st,end,pri);
	} else if ((pri=find_leftest(st,end,"?"))) {
		me->to.token=binoper(pri);
		me->toket=-1;
		if (!(me->down=gettree(st,pri))) tokerror(st,end,"cannon parse");
		struct token *col=find_colon(pri,end);
		if (!(me->down->next=gettree(pri->next,col))) tokerror(st,end,"cannon parse");
		if (!(me->down->next->next=gettree(col->next,end))) tokerror(st,end,"cannon parse");
	} else if ((pri=find_rightest(st,end,"||"))) {
		get_bintree(me,st,end,pri);
	} else if ((pri=find_rightest(st,end,"&&"))) {
		get_bintree(me,st,end,pri);
	} else if ((pri=find_rightest(st,end,"|"))) {
		get_bintree(me,st,end,pri);
	} else if ((pri=find_rightest(st,end,"^"))) {
		get_bintree(me,st,end,pri);
	} else if ((pri=find_rightest(endbr(st,end)->next,end,"&"))) {
		get_bintree(me,st,end,pri);
	} else if ((pri=find_rightest(st,end,"!= =="))) {
		get_bintree(me,st,end,pri);
	} else if ((pri=find_rightest(st,end,"< <= => >"))) {
		get_bintree(me,st,end,pri);
	} else if ((pri=find_rightest(st,end,"<< >>"))) {
		get_bintree(me,st,end,pri);
	} else if ((pri=find_rightest(endbr(st,end)->next,end,"+ -"))) {
		get_bintree(me,st,end,pri);
	} else if ((pri=find_rightest(st,end,"/ %"))) {
		get_bintree(me,st,end,pri);
	} else if ((pri=find_rightest(endbr(st,end)->next,end,"*"))) {
		get_bintree(me,st,end,pri);
	} else if (tokis(st,"++ -- + - ! ~ * &")) {
		me->to.token=unaryoper(st);
		me->toket=-1;
		if (!(me->down=gettree(st->next,end))) tokerror(st,end,"cannon parse");
	} else if (tokis(end->prev,"]")) {
		me->down=calloc(1,sizeof(*me));
		get_bintree(me->down,st,end->prev,stabr(st,end));
		typetree(me->down);
		me->to.token=&operure;
		me->toket=-1;
	} else if (tokis(end->prev,"++ --")) {
		me->to.token=sufoper(end->prev);
		me->toket=-1;
		if (!(me->down=gettree(st,end->prev))) tokerror(st,end,"cannon parse");
	} else if (tokis(end->prev->prev,".")) {
		if (!(me->down=gettree(st,end->prev->prev))) tokerror(st,end,"cannon parse");
		if (me->down->type.pt) treerror(me->down,"pointer cannot have members");
		struct mem *mem=find_member(me->down->type.bt,end->prev);
		if (!mem) treerror(me->down,"invalid member");
		me->down->next=calloc(1,sizeof(*me));
		me->down->next->to.val=mem->offset;
		me->down->next->toket=2;
		me->type=mem->type;
		me->type.pt+=me->down->type.pt;
		me->to.func=get_func("operdot(void,int)");
		me->toket=1;
		return me;
	} else if (tokis(end->prev->prev,"->")) {
		me->down=calloc(1,sizeof(*me));
		if (!(me->down->down=gettree(st,end->prev->prev))) tokerror(st,end,"cannon parse");
		if (me->down->down->type.pt!=1) treerror(me->down->down,"pointer cannot have members");
		me->down->type.bt=me->down->down->type.bt;
		me->down->type.pt=0;
		me->down->type.lv=1;
		me->down->to.func=get_func("operure(same*)");
		me->down->toket=1;
		struct mem *mem=find_member(me->down->down->type.bt,end->prev);
		if (!mem) treerror(me->down,"invalid member");
		me->down->next=calloc(1,sizeof(*me));
		me->down->next->to.val=mem->offset;
		me->down->next->toket=2;
		me->type=mem->type;
		me->type.lv=1;
		me->to.func=get_func("operdot(void,int)");
		me->toket=1;
		return me;
	} else tokerror(st,end,"cannon parse");
	typetree(me);
	return me;
}

void freetree(struct tree *tree) {
	if (!tree) return;
	freetree(tree->down);
	freetree(tree->next);
	free(tree);
	return;
}
